package com.cugmarket.socket;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cugmarket.constant.MessageConstant;
import com.cugmarket.constant.RedisConstants;
import com.cugmarket.exception.BaseException;
import com.cugmarket.service.ChatMessageService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Component
@ServerEndpoint(value = "/websocket/{fromUserId}")
public class WebSocketServer {

    private static StringRedisTemplate stringRedisTemplate;

    @Resource
    public void setStringRedisTemplate(StringRedisTemplate stringRedisTemplate) {
        WebSocketServer.stringRedisTemplate = stringRedisTemplate;
    }

    private static ChatMessageService chatMessageService;

    @Resource
    public void setChatMessageService(ChatMessageService chatMessageService) {
        WebSocketServer.chatMessageService = chatMessageService;
    }

    // 存储所有 WebSocket 连接
    private static final Map<String, Session> SESSIONS = new ConcurrentHashMap<>();
    // 标识当前聊天列表的id
    private String chatListId;
    // 标识当前用户信息
    private String fromUserId;


    /**
     * 建立连接时候的回调
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("fromUserId") String fromUserId) {
        this.fromUserId = fromUserId;
        String msgToken = generateKey(fromUserId);
        SESSIONS.put(msgToken, session);
        log.info("WebSocket 连接已建立，建立人是：userId={}，当前在线人数为：{}", fromUserId, SESSIONS.size());
    }

    /**
     * 接收到来自客户端消息的回调
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("收到消息: fromUserId={}, message={}", fromUserId, message);
        // 解析消息
        JSONObject jsonObject = JSON.parseObject(message);

        // 解析聊天列表ID
        String chatListId = jsonObject.getString("chatListId");
        this.chatListId = chatListId;
        // 获取目标用户的 key 和 session
        String toUserId = jsonObject.getString("toUserId");
        // 生成消息发送目标的token
        String targetToken = generateKey(toUserId);
        // 在SESSIONS中查找目标用户的session
        Session targetSession = SESSIONS.get(targetToken);
        // 将消息存入 Redis,且统一设为未读
        jsonObject.put("isRead", "0"); // 未读

        if (targetSession != null) {
            // 说明对方用户此时的Socket连接处于打开状态,那就给客户端推送消息
            try {
                targetSession.getBasicRemote().sendText(jsonObject.toJSONString());
                log.info("消息已发送: fromUserId={}, toUserId={},消息：{}", fromUserId, toUserId, message);
            } catch (IOException e) {
                log.error("推送消息失败: 目标用户的targetToken={}, error={}", targetToken, e.getMessage(), e);
            }
        }
        // 存入 Redis
        String chatListIdToken = generateKey(chatListId);
        stringRedisTemplate.opsForList().rightPush(chatListIdToken, jsonObject.toJSONString());
    }


    /**
     * 关闭连接时候的回调
     */
    @OnClose
    public void onClose(Session session) {
        String chatListToken = generateKey(chatListId);
        try {
            // 从 Redis 中获取当前用户发送的所有消息列表
            ListOperations<String, String> operations = stringRedisTemplate.opsForList();
            List<String> messageList = operations.range(chatListToken, 0, -1);

            if (messageList != null && !messageList.isEmpty()) {
                // 将消息列表存入数据库
                boolean saveResult = chatMessageService.saveMessages(messageList);
                if (saveResult) {
                    // 保存成功后删除 Redis 中的消息
                    stringRedisTemplate.delete(chatListToken);
                    log.info("ID为：{} 的聊天消息已成功保存到数据库并清理Redis: ", chatListId);
                } else {
                    log.warn("ID为：{} 的聊天消息保存到数据库失败，消息列表大小: {}", chatListId, messageList.size());
                }
            } else {
                log.info("Redis 中未找到ID为：{} 的聊天消息", chatListId);
            }
        } catch (Exception e) {
            log.error("关闭 WebSocket 连接时发生错误: userId={}, error={}", fromUserId, e.getMessage(), e);
        } finally {
            // 从 SESSIONS 中移除用户连接
            String sessionKey = generateKey(fromUserId);
            SESSIONS.remove(sessionKey);
            log.info("WebSocket 连接已关闭: userId={}", fromUserId);
        }
    }

    /**
     * 发生错误时候的回调
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("WebSocket 发生错误: userId={}, error={}", fromUserId, error.getMessage());
    }

    /**
     * 生成唯一标识
     */
    private String generateKey(String userId) {
        return RedisConstants.CHAT_LIST_KEY + userId;
    }

    /**
     * 广播消息
     */
    private void broadcastMessage(String message) {
        SESSIONS.forEach((key, session) -> {
            try {
                session.getBasicRemote().sendText(message);
            } catch (IOException e) {
                log.error("广播消息失败: key={}, error={}", key, e.getMessage(), e);
            }
        });
    }
}
